/*     */ package com.zimbra.cs.redolog.logger;
/*     */ 
/*     */ import com.zimbra.common.localconfig.DebugConfig;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.redolog.CommitId;
/*     */ import com.zimbra.cs.redolog.RedoCommitCallback;
/*     */ import com.zimbra.cs.redolog.RedoConfig;
/*     */ import com.zimbra.cs.redolog.RedoLogManager;
/*     */ import com.zimbra.cs.redolog.RolloverManager;
/*     */ import com.zimbra.cs.redolog.op.CommitTxn;
/*     */ import com.zimbra.cs.redolog.op.RedoableOp;
/*     */ import com.zimbra.cs.util.Zimbra;
/*     */ import java.io.File;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.io.RandomAccessFile;
/*     */ import java.nio.channels.FileChannel;
/*     */ import java.util.Iterator;
/*     */ import java.util.LinkedHashMap;
/*     */ import java.util.Map.Entry;
/*     */ import java.util.Set;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class FileLogWriter
/*     */   implements LogWriter
/*     */ {
/*     */   private static String sServerId;
/*     */   protected RedoLogManager mRedoLogMgr;
/*     */   
/*     */   static
/*     */   {
/*     */     try
/*     */     {
/*  61 */       sServerId = Provisioning.getInstance().getLocalServer().getId();
/*     */     } catch (ServiceException e) {
/*  63 */       ZimbraLog.redolog.error("Unable to get local server ID", e);
/*  64 */       sServerId = "unknown";
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*  71 */   private final Object mLock = new Object();
/*     */   
/*     */ 
/*  74 */   private final Object mFsyncCond = new Object();
/*     */   
/*     */   private FileHeader mHeader;
/*     */   
/*     */   private long mFirstOpTstamp;
/*     */   
/*     */   private long mLastOpTstamp;
/*     */   
/*     */   private long mCreateTime;
/*     */   
/*     */   private File mFile;
/*     */   
/*     */   private RandomAccessFile mRAF;
/*     */   
/*     */   private long mFileSize;
/*     */   private long mLastLogTime;
/*     */   private long mFsyncIntervalMS;
/*     */   private boolean mFsyncDisabled;
/*     */   private FsyncThread mFsyncer;
/*     */   private int mLogSeq;
/*     */   private int mFsyncSeq;
/*     */   private int mLogCount;
/*     */   private int mFsyncCount;
/*     */   private CommitNotifyQueue mCommitNotifyQueue;
/*     */   private int mLastOpMboxId;
/*     */   private boolean mNoStat;
/*     */   
/*     */   public FileLogWriter(RedoLogManager redoLogMgr, File logfile, long fsyncIntervalMS)
/*     */   {
/* 103 */     this.mRedoLogMgr = redoLogMgr;
/*     */     
/* 105 */     this.mHeader = new FileHeader(sServerId);
/* 106 */     this.mFile = logfile;
/* 107 */     this.mFileSize = this.mFile.length();
/* 108 */     this.mLastLogTime = this.mFile.lastModified();
/*     */     
/* 110 */     this.mFsyncIntervalMS = fsyncIntervalMS;
/* 111 */     this.mFsyncDisabled = DebugConfig.disableRedoLogFsync;
/*     */     
/* 113 */     this.mFsyncCount = (this.mLogCount = 0);
/*     */     
/* 115 */     this.mCommitNotifyQueue = new CommitNotifyQueue(100);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public boolean isEmpty()
/*     */     throws IOException
/*     */   {
/* 155 */     return getSize() <= 512L;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public boolean exists()
/*     */   {
/* 162 */     return this.mFile.exists();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public String getAbsolutePath()
/*     */   {
/* 169 */     return this.mFile.getAbsolutePath();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public boolean renameTo(File dest)
/*     */   {
/* 176 */     return this.mFile.renameTo(dest);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public boolean delete()
/*     */   {
/* 183 */     return this.mFile.delete();
/*     */   }
/*     */   
/*     */ 
/*     */   public synchronized void open()
/*     */     throws IOException
/*     */   {
/* 190 */     synchronized (this.mLock) {
/* 191 */       if (this.mRAF != null) { return;
/*     */       }
/* 193 */       this.mRAF = new RandomAccessFile(this.mFile, "rw");
/*     */       
/* 195 */       if (this.mRAF.length() >= 512L) {
/* 196 */         this.mHeader.read(this.mRAF);
/* 197 */         this.mCreateTime = this.mHeader.getCreateTime();
/* 198 */         if (this.mCreateTime == 0L) {
/* 199 */           this.mCreateTime = System.currentTimeMillis();
/* 200 */           this.mHeader.setCreateTime(this.mCreateTime);
/*     */         }
/* 202 */         this.mFirstOpTstamp = this.mHeader.getFirstOpTstamp();
/* 203 */         this.mLastOpTstamp = this.mHeader.getLastOpTstamp();
/*     */       } else {
/* 205 */         this.mCreateTime = System.currentTimeMillis();
/* 206 */         this.mHeader.setCreateTime(this.mCreateTime);
/* 207 */         this.mHeader.setSequence(this.mRedoLogMgr.getCurrentLogSequence());
/*     */       }
/* 209 */       this.mHeader.setOpen(true);
/* 210 */       this.mHeader.write(this.mRAF);
/*     */       
/*     */ 
/* 213 */       long len = this.mRAF.length();
/* 214 */       this.mRAF.seek(len);
/* 215 */       this.mFileSize = len;
/*     */       
/* 217 */       this.mLogSeq = (this.mFsyncSeq = 0);
/*     */     }
/*     */     
/* 220 */     if (this.mFsyncIntervalMS > 0L) {
/* 221 */       startFsyncThread();
/*     */     }
/*     */   }
/*     */   
/*     */   public synchronized void close()
/*     */     throws IOException
/*     */   {
/* 228 */     stopFsyncThread();
/*     */     
/* 230 */     synchronized (this.mLock) {
/* 231 */       if (this.mRAF != null) {
/* 232 */         if (this.mLastOpTstamp != 0L)
/* 233 */           this.mHeader.setLastOpTstamp(this.mLastOpTstamp);
/* 234 */         this.mHeader.setOpen(false);
/* 235 */         this.mHeader.setFileSize(this.mRAF.length());
/* 236 */         this.mHeader.write(this.mRAF);
/*     */         
/* 238 */         this.mRAF.getChannel().force(true);
/* 239 */         this.mRAF.close();
/* 240 */         this.mRAF = null;
/*     */       } else {
/* 242 */         return;
/*     */       }
/*     */     }
/*     */     
/* 246 */     if ((!this.mNoStat) && (this.mLogCount > 0) && (ZimbraLog.redolog.isDebugEnabled())) {
/* 247 */       ZimbraLog.redolog.debug("Logged: " + this.mLogCount + " items, " + this.mFsyncCount + " fsyncs");
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void log(RedoableOp op, InputStream data, boolean synchronous)
/*     */     throws IOException
/*     */   {
/* 275 */     boolean sameMboxAsLastOp = false;
/*     */     int seq;
/* 277 */     synchronized (this.mLock) {
/* 278 */       if (this.mRAF == null) {
/* 279 */         throw new IOException("Redolog file closed");
/*     */       }
/*     */       
/* 282 */       long tstamp = op.getTimestamp();
/* 283 */       this.mLastOpTstamp = Math.max(tstamp, this.mLastOpTstamp);
/* 284 */       if (this.mFirstOpTstamp == 0L) {
/* 285 */         this.mFirstOpTstamp = tstamp;
/* 286 */         this.mHeader.setFirstOpTstamp(this.mFirstOpTstamp);
/* 287 */         this.mHeader.setLastOpTstamp(this.mLastOpTstamp);
/* 288 */         long pos = this.mRAF.getFilePointer();
/* 289 */         this.mHeader.write(this.mRAF);
/* 290 */         this.mRAF.seek(pos);
/*     */       }
/*     */       
/* 293 */       this.mLogSeq += 1;
/* 294 */       this.mLogCount += 1;
/* 295 */       seq = this.mLogSeq;
/*     */       
/* 297 */       byte[] buf = new byte['Ѐ'];
/* 298 */       int numRead; while ((numRead = data.read(buf)) >= 0) {
/* 299 */         this.mRAF.write(buf, 0, numRead);
/* 300 */         this.mFileSize += numRead;
/*     */       }
/* 302 */       data.close();
/*     */       
/*     */ 
/*     */ 
/* 306 */       if ((op instanceof CommitTxn)) {
/* 307 */         CommitTxn cmt = (CommitTxn)op;
/* 308 */         RedoCommitCallback cb = cmt.getCallback();
/* 309 */         if (cb != null) {
/* 310 */           long redoSeq = this.mRedoLogMgr.getRolloverManager().getCurrentSequence();
/* 311 */           CommitId cid = new CommitId(redoSeq, (CommitTxn)op);
/* 312 */           Notif notif = new Notif(cb, cid);
/*     */           
/*     */ 
/* 315 */           this.mCommitNotifyQueue.push(notif);
/*     */         }
/*     */       }
/*     */       
/* 319 */       this.mLastLogTime = System.currentTimeMillis();
/*     */       
/* 321 */       sameMboxAsLastOp = this.mLastOpMboxId == op.getMailboxId();
/* 322 */       this.mLastOpMboxId = op.getMailboxId();
/*     */     }
/*     */     
/*     */ 
/* 326 */     if (!synchronous) {
/* 327 */       return;
/*     */     }
/* 329 */     if (this.mFsyncIntervalMS > 0L) {
/* 330 */       if (!sameMboxAsLastOp)
/*     */       {
/*     */         try
/*     */         {
/* 334 */           synchronized (this.mFsyncCond) {
/* 335 */             this.mFsyncCond.wait(10000L);
/*     */           }
/*     */         } catch (InterruptedException e) {
/* 338 */           ZimbraLog.redolog.info("Thread interrupted during fsync");
/*     */         }
/* 340 */         synchronized (this.mLock)
/*     */         {
/* 342 */           if (seq > this.mFsyncSeq) {
/* 343 */             fsync();
/*     */           }
/*     */           
/*     */         }
/*     */       }
/*     */       else
/*     */       {
/* 350 */         fsync();
/*     */       }
/*     */     }
/*     */     else {
/* 354 */       fsync();
/*     */     }
/*     */   }
/*     */   
/*     */   public void flush()
/*     */     throws IOException
/*     */   {
/* 361 */     fsync();
/*     */   }
/*     */   
/*     */   public void noStat(boolean b)
/*     */   {
/* 366 */     this.mNoStat = b;
/*     */   }
/*     */   
/*     */   public synchronized File rollover(LinkedHashMap activeOps)
/*     */     throws IOException
/*     */   {
/* 372 */     RolloverManager romgr = this.mRedoLogMgr.getRolloverManager();
/*     */     
/* 374 */     long lastSeq = getSequence();
/*     */     
/*     */ 
/* 377 */     noStat(true);
/* 378 */     close();
/*     */     
/* 380 */     romgr.incrementSequence();
/*     */     
/* 382 */     String currentPath = this.mFile.getAbsolutePath();
/*     */     
/*     */ 
/* 385 */     File tempLogfile = new File(this.mFile.getParentFile(), romgr.getTempFilename(lastSeq + 1L));
/* 386 */     FileLogWriter tempLogger = new FileLogWriter(this.mRedoLogMgr, tempLogfile, 0L);
/*     */     
/* 388 */     tempLogger.open();
/* 389 */     tempLogger.noStat(true);
/*     */     
/*     */ 
/*     */ 
/* 393 */     Set opsSet = activeOps.entrySet();
/* 394 */     for (Iterator it = opsSet.iterator(); it.hasNext();) {
/* 395 */       Map.Entry entry = (Map.Entry)it.next();
/* 396 */       RedoableOp op = (RedoableOp)entry.getValue();
/* 397 */       tempLogger.log(op, op.getInputStream(), false);
/*     */     }
/* 399 */     tempLogger.close();
/*     */     
/*     */ 
/* 402 */     File rolloverFile = romgr.getRolloverFile(lastSeq);
/* 403 */     if (RedoConfig.redoLogDeleteOnRollover())
/*     */     {
/*     */ 
/* 406 */       if (!this.mFile.delete())
/* 407 */         throw new IOException("Unable to delete current redo log " + this.mFile.getAbsolutePath());
/*     */     } else {
/* 409 */       File destDir = rolloverFile.getParentFile();
/* 410 */       if ((destDir != null) && (!destDir.exists()))
/* 411 */         destDir.mkdirs();
/* 412 */       if (!this.mFile.renameTo(rolloverFile)) {
/* 413 */         throw new IOException("Unable to rename current redo log to " + rolloverFile.getAbsolutePath());
/*     */       }
/*     */     }
/*     */     
/* 417 */     String tempPath = tempLogfile.getAbsolutePath();
/* 418 */     this.mFile = new File(currentPath);
/* 419 */     if (!tempLogfile.renameTo(this.mFile)) {
/* 420 */       throw new IOException("Unable to rename " + tempPath + " to " + currentPath);
/*     */     }
/*     */     
/* 423 */     open();
/* 424 */     noStat(false);
/*     */     
/* 426 */     return rolloverFile;
/*     */   }
/*     */   
/*     */   public synchronized void enableFsync() throws IOException {
/* 430 */     startFsyncThread();
/* 431 */     fsync();
/*     */   }
/*     */   
/*     */   public synchronized void disableFsync() throws IOException {
/* 435 */     fsync();
/* 436 */     stopFsyncThread();
/*     */   }
/*     */   
/*     */   private synchronized void startFsyncThread() {
/* 440 */     if ((this.mFsyncer == null) && (this.mFsyncIntervalMS > 0L)) {
/* 441 */       this.mFsyncer = new FsyncThread(this.mFsyncIntervalMS);
/* 442 */       this.mFsyncer.start();
/*     */     }
/*     */   }
/*     */   
/*     */   private synchronized void stopFsyncThread() {
/* 447 */     if (this.mFsyncer != null) {
/* 448 */       this.mFsyncer.stopThread();
/* 449 */       this.mFsyncer = null;
/*     */     }
/*     */   }
/*     */   
/*     */   private void fsync() throws IOException
/*     */   {
/* 455 */     boolean fsyncNeeded = false;
/* 456 */     int seq = 0;
/* 457 */     synchronized (this.mLock) {
/* 458 */       if (this.mFsyncSeq < this.mLogSeq) {
/* 459 */         if (this.mRAF == null)
/* 460 */           throw new IOException("Redolog file closed");
/* 461 */         fsyncNeeded = true;
/* 462 */         seq = this.mLogSeq;
/* 463 */         if (!this.mFsyncDisabled)
/* 464 */           this.mFsyncCount += 1;
/*     */       }
/*     */     }
/* 467 */     if (fsyncNeeded) {
/* 468 */       if (!this.mFsyncDisabled) {
/* 469 */         synchronized (this.mLock) {
/* 470 */           if (this.mRAF != null) {
/* 471 */             this.mRAF.getChannel().force(false);
/*     */           } else
/* 473 */             throw new IOException("Redolog file closed");
/* 474 */           this.mCommitNotifyQueue.flush(false);
/*     */         }
/*     */       }
/* 477 */       synchronized (this.mLock) {
/* 478 */         this.mFsyncSeq = seq;
/*     */       }
/* 480 */       if (this.mFsyncIntervalMS > 0L) {
/* 481 */         synchronized (this.mFsyncCond) {
/* 482 */           this.mFsyncCond.notifyAll();
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   /* Error */
/*     */   public long getSequence()
/*     */   {
/*     */     // Byte code:
/*     */     //   0: aload_0
/*     */     //   1: getfield 5	com/zimbra/cs/redolog/logger/FileLogWriter:mLock	Ljava/lang/Object;
/*     */     //   4: dup
/*     */     //   5: astore_1
/*     */     //   6: monitorenter
/*     */     //   7: aload_0
/*     */     //   8: getfield 11	com/zimbra/cs/redolog/logger/FileLogWriter:mHeader	Lcom/zimbra/cs/redolog/logger/FileHeader;
/*     */     //   11: invokevirtual 24	com/zimbra/cs/redolog/logger/FileHeader:getSequence	()J
/*     */     //   14: aload_1
/*     */     //   15: monitorexit
/*     */     //   16: lreturn
/*     */     //   17: astore_2
/*     */     //   18: aload_1
/*     */     //   19: monitorexit
/*     */     //   20: aload_2
/*     */     //   21: athrow
/*     */     // Line number table:
/*     */     //   Java source line #119	-> byte code offset #0
/*     */     //   Java source line #120	-> byte code offset #7
/*     */     //   Java source line #121	-> byte code offset #17
/*     */     // Local variable table:
/*     */     //   start	length	slot	name	signature
/*     */     //   0	22	0	this	FileLogWriter
/*     */     //   5	14	1	Ljava/lang/Object;	Object
/*     */     //   17	4	2	localObject1	Object
/*     */     // Exception table:
/*     */     //   from	to	target	type
/*     */     //   7	16	17	finally
/*     */     //   17	20	17	finally
/*     */   }
/*     */   
/*     */   /* Error */
/*     */   public long getSize()
/*     */   {
/*     */     // Byte code:
/*     */     //   0: aload_0
/*     */     //   1: getfield 5	com/zimbra/cs/redolog/logger/FileLogWriter:mLock	Ljava/lang/Object;
/*     */     //   4: dup
/*     */     //   5: astore_1
/*     */     //   6: monitorenter
/*     */     //   7: aload_0
/*     */     //   8: getfield 13	com/zimbra/cs/redolog/logger/FileLogWriter:mFileSize	J
/*     */     //   11: aload_1
/*     */     //   12: monitorexit
/*     */     //   13: lreturn
/*     */     //   14: astore_2
/*     */     //   15: aload_1
/*     */     //   16: monitorexit
/*     */     //   17: aload_2
/*     */     //   18: athrow
/*     */     // Line number table:
/*     */     //   Java source line #128	-> byte code offset #0
/*     */     //   Java source line #129	-> byte code offset #7
/*     */     //   Java source line #130	-> byte code offset #14
/*     */     // Local variable table:
/*     */     //   start	length	slot	name	signature
/*     */     //   0	19	0	this	FileLogWriter
/*     */     //   5	11	1	Ljava/lang/Object;	Object
/*     */     //   14	4	2	localObject1	Object
/*     */     // Exception table:
/*     */     //   from	to	target	type
/*     */     //   7	13	14	finally
/*     */     //   14	17	14	finally
/*     */   }
/*     */   
/*     */   /* Error */
/*     */   public long getCreateTime()
/*     */   {
/*     */     // Byte code:
/*     */     //   0: aload_0
/*     */     //   1: getfield 5	com/zimbra/cs/redolog/logger/FileLogWriter:mLock	Ljava/lang/Object;
/*     */     //   4: dup
/*     */     //   5: astore_1
/*     */     //   6: monitorenter
/*     */     //   7: aload_0
/*     */     //   8: getfield 25	com/zimbra/cs/redolog/logger/FileLogWriter:mCreateTime	J
/*     */     //   11: aload_1
/*     */     //   12: monitorexit
/*     */     //   13: lreturn
/*     */     //   14: astore_2
/*     */     //   15: aload_1
/*     */     //   16: monitorexit
/*     */     //   17: aload_2
/*     */     //   18: athrow
/*     */     // Line number table:
/*     */     //   Java source line #137	-> byte code offset #0
/*     */     //   Java source line #138	-> byte code offset #7
/*     */     //   Java source line #139	-> byte code offset #14
/*     */     // Local variable table:
/*     */     //   start	length	slot	name	signature
/*     */     //   0	19	0	this	FileLogWriter
/*     */     //   5	11	1	Ljava/lang/Object;	Object
/*     */     //   14	4	2	localObject1	Object
/*     */     // Exception table:
/*     */     //   from	to	target	type
/*     */     //   7	13	14	finally
/*     */     //   14	17	14	finally
/*     */   }
/*     */   
/*     */   /* Error */
/*     */   public long getLastLogTime()
/*     */   {
/*     */     // Byte code:
/*     */     //   0: aload_0
/*     */     //   1: getfield 5	com/zimbra/cs/redolog/logger/FileLogWriter:mLock	Ljava/lang/Object;
/*     */     //   4: dup
/*     */     //   5: astore_1
/*     */     //   6: monitorenter
/*     */     //   7: aload_0
/*     */     //   8: getfield 15	com/zimbra/cs/redolog/logger/FileLogWriter:mLastLogTime	J
/*     */     //   11: aload_1
/*     */     //   12: monitorexit
/*     */     //   13: lreturn
/*     */     //   14: astore_2
/*     */     //   15: aload_1
/*     */     //   16: monitorexit
/*     */     //   17: aload_2
/*     */     //   18: athrow
/*     */     // Line number table:
/*     */     //   Java source line #146	-> byte code offset #0
/*     */     //   Java source line #147	-> byte code offset #7
/*     */     //   Java source line #148	-> byte code offset #14
/*     */     // Local variable table:
/*     */     //   start	length	slot	name	signature
/*     */     //   0	19	0	this	FileLogWriter
/*     */     //   5	11	1	Ljava/lang/Object;	Object
/*     */     //   14	4	2	localObject1	Object
/*     */     // Exception table:
/*     */     //   from	to	target	type
/*     */     //   7	13	14	finally
/*     */     //   14	17	14	finally
/*     */   }
/*     */   
/*     */   private class FsyncThread
/*     */     extends Thread
/*     */   {
/*     */     private long mSleepMS;
/*     */     private Object mFsyncLock;
/*     */     private boolean mRunning;
/*     */     private static final long MIN_SLEEP_MILLIS = 1L;
/*     */     private static final long MAX_SLEEP_MILLIS = 1000L;
/*     */     
/*     */     public FsyncThread(long fsyncIntervalMS)
/*     */     {
/* 502 */       super();
/*     */       
/* 504 */       if (fsyncIntervalMS < 1L) {
/* 505 */         ZimbraLog.redolog.warn("Invalid fsync thread sleep interval %dms; using %dms instead", new Object[] { Long.valueOf(fsyncIntervalMS), Long.valueOf(1L) });
/*     */         
/* 507 */         this.mSleepMS = 1L;
/* 508 */       } else if (fsyncIntervalMS > 1000L) {
/* 509 */         ZimbraLog.redolog.warn("Fsync thread sleep interval %ms is too long; using %dms instead", new Object[] { Long.valueOf(fsyncIntervalMS), Long.valueOf(1000L) });
/*     */         
/* 511 */         this.mSleepMS = 1000L;
/*     */       } else {
/* 513 */         this.mSleepMS = fsyncIntervalMS;
/*     */       }
/* 515 */       this.mFsyncLock = new Object();
/* 516 */       this.mRunning = true;
/*     */     }
/*     */     
/*     */     public void run() {
/* 520 */       boolean running = true;
/* 521 */       ZimbraLog.redolog.info("Starting fsync thread with interval %d", new Object[] { Long.valueOf(this.mSleepMS) });
/* 522 */       while (running)
/*     */       {
/*     */         try {
/* 525 */           ZimbraLog.redolog.trace("Sleeping for %s", new Object[] { Long.valueOf(this.mSleepMS) });
/* 526 */           Thread.sleep(this.mSleepMS);
/* 527 */           ZimbraLog.redolog.trace("Slept for %s running? %s", new Object[] { Long.valueOf(this.mSleepMS), Boolean.valueOf(this.mRunning) });
/*     */         } catch (InterruptedException e) {
/* 529 */           ZimbraLog.redolog.warn("Sync thread interrupted", e);
/*     */         }
/*     */         try
/*     */         {
/* 533 */           FileLogWriter.this.fsync();
/*     */         } catch (IOException e) {
/* 535 */           String message = "Error while fsyncing " + FileLogWriter.this.mFile.getAbsolutePath() + "; Aborting.";
/* 536 */           Zimbra.halt(message, e);
/*     */         }
/*     */         
/* 539 */         synchronized (this.mFsyncLock) {
/* 540 */           running = this.mRunning;
/*     */         }
/*     */       }
/* 543 */       ZimbraLog.redolog.info("fsync thread exiting");
/*     */     }
/*     */     
/*     */     public void stopThread()
/*     */     {
/* 548 */       synchronized (this.mFsyncLock) {
/* 549 */         this.mRunning = false;
/*     */       }
/*     */       try {
/* 552 */         while (isAlive()) {
/* 553 */           if (ZimbraLog.redolog.isTraceEnabled()) {
/* 554 */             ZimbraLog.redolog.trace("waiting for %s to finish. running? %s", new Object[] { getName(), Boolean.valueOf(this.mRunning) });
/*     */           } else {
/* 556 */             ZimbraLog.redolog.info("waiting for %s to finish.", new Object[] { getName() });
/*     */           }
/* 558 */           join(60000L);
/*     */         }
/* 560 */         ZimbraLog.redolog.info("%s finished", new Object[] { getName() });
/*     */       } catch (InterruptedException e) {
/* 562 */         ZimbraLog.redolog.warn("InterruptedException while stopping FsyncThread", e);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */   private static class Notif
/*     */   {
/*     */     private RedoCommitCallback mCallback;
/*     */     private CommitId mCommitId;
/*     */     
/*     */     public Notif(RedoCommitCallback callback, CommitId cid)
/*     */     {
/* 575 */       this.mCallback = callback;
/* 576 */       this.mCommitId = cid; }
/*     */     
/* 578 */     public RedoCommitCallback getCallback() { return this.mCallback; }
/* 579 */     public CommitId getCommitId() { return this.mCommitId; }
/*     */   }
/*     */   
/*     */   private class CommitNotifyQueue {
/* 583 */     private FileLogWriter.Notif[] mQueue = new FileLogWriter.Notif[100];
/*     */     private int mHead;
/*     */     private int mTail;
/*     */     private boolean mFull;
/*     */     
/*     */     public CommitNotifyQueue(int size) {
/* 589 */       this.mQueue = new FileLogWriter.Notif[size];
/* 590 */       this.mHead = (this.mTail = 0);
/* 591 */       this.mFull = false;
/*     */     }
/*     */     
/*     */     public synchronized void push(FileLogWriter.Notif notif) throws IOException {
/* 595 */       if (notif != null) {
/* 596 */         if (this.mFull) flush(true);
/* 597 */         assert (!this.mFull);
/* 598 */         this.mQueue[this.mTail] = notif;
/* 599 */         this.mTail += 1;
/* 600 */         this.mTail %= this.mQueue.length;
/* 601 */         this.mFull = (this.mTail == this.mHead);
/*     */       }
/*     */     }
/*     */     
/*     */     private synchronized FileLogWriter.Notif pop() {
/* 606 */       if ((this.mHead == this.mTail) && (!this.mFull)) return null;
/* 607 */       FileLogWriter.Notif n = this.mQueue[this.mHead];
/* 608 */       this.mQueue[this.mHead] = null;
/* 609 */       this.mHead += 1;
/* 610 */       this.mHead %= this.mQueue.length;
/* 611 */       this.mFull = false;
/* 612 */       return n;
/*     */     }
/*     */     
/*     */     public synchronized void flush(boolean fsync) throws IOException {
/* 616 */       if (fsync)
/* 617 */         FileLogWriter.this.fsync();
/*     */       FileLogWriter.Notif notif;
/* 619 */       while ((notif = pop()) != null) {
/* 620 */         RedoCommitCallback cb = notif.getCallback();
/* 621 */         assert (cb != null);
/*     */         try {
/* 623 */           cb.callback(notif.getCommitId());
/*     */         } catch (OutOfMemoryError e) {
/* 625 */           Zimbra.halt("out of memory", e);
/*     */         } catch (Throwable t) {
/* 627 */           ZimbraLog.misc.error("Error while making commit callback", t);
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/redolog/logger/FileLogWriter.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */